package com.li.service.impl;
import cn.hutool.core.util.IdUtil;
import com.li.service.RedisLock01Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//v2.0
/**
 *问题:见todo处 ,共3条
 */
@Slf4j
@Service
public class RedisLock01ServiceImpl2 implements RedisLock01Service {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Value("${server.port}")
    private String port;
//    private Lock lock = new ReentrantLock();
    @Override
    public String sale() {
        String retMessage = "";
        String key = "redisLock";
        //使用uuid:线程id作为锁值
        String uuidValue = IdUtil.simpleUUID() + ":" + Thread.currentThread().getId();
        //设置键值对(key,uuidValue) ,如果key存在 返回false ,如果key不存在 创建键值对 返回true
        Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, uuidValue);//todo(3) 如果线程A拿到锁执行到if (!flag)对应的else块中,然后A线程由于机器负载无法及时释放锁,导致线程B无法拿到锁,进入死循环
        if (!flag) {//todo (1)使用if判断,会导致虚假唤醒现象
            try {
                TimeUnit.MILLISECONDS.sleep(20);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return sale();//todo(2) 递归调用，会导致栈溢出 ,高并发下不要用递归调用!

        } else {
            try {
                //查询库存信息
                String result = redisTemplate.opsForValue().get("inventory");
                //判断库存是否足够
                Integer inventoryNum = result == null ? 0 : Integer.parseInt(result);
                if (inventoryNum > 0) {
                    redisTemplate.opsForValue().set("inventory", String.valueOf(inventoryNum - 1));
                    retMessage = "成功售出商品，当前库存为：" + redisTemplate.opsForValue().get("inventory") + "，购买端口为：" + port;
                    System.out.println(retMessage);
                } else {
                    retMessage = "库存不足，当前库存为：" + redisTemplate.opsForValue().get("inventory") + "，购买端口为：" + port;
                    System.out.println(retMessage);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                //释放锁
                redisTemplate.delete(key);
            }
            return retMessage;
        }
    }

}
